<?php
require_once dirname(__FILE__).'/Comment.php';
require_once dirname(__FILE__).'/Example.php';

/**
 * doctest 주석 분석기
 *
 * parse 메소드는 주석을 분석하여 DocTestExample 객체의 배열을 돌려줍니다.
 * php> $parser = new DocTestParser;
 * php> $examples = $parser->parse(new DocTestComment("* php> 1 + 1\n* 2\n* php> doSomething();\n* php> doSomething();", 1));
 * php> $examples[0]->source
 * "1 + 1"
 * php> $examples[0]->expect
 * "2"
 * php> $examples[2]->source
 * "doSomething();"
 * php> $examples[2]->expect
 * NULL
 * php> $examples[2]->lineNumber
 * 4
 */
class DocTestParser {
	function parse($comment) {
		$examples = array();
		$current_source = NULL;
		$this->lines = explode("\n", $comment->text);
		$this->lineno = 0;
		while ($this->hasNextLine()) {
			if ($this->shouldParseLine() && $this->isSourceLine()) {
				$line = $this->getCurrentLine();
				list(, $source) = explode('php>', $line, 2);
				$example = new DocTestExample(trim($source), NULL, $this->lineno + $comment->lineNumber);
				$this->nextLine();
				if ($this->shouldParseLine() && !$this->isSourceLine()) {
					list(, $expect) = explode('*', $this->getCurrentLine(), 2);
					$example->expect = trim($expect);
				} else {
					$this->ungetLine();
				}
				$examples[] = $example;
			}
			$this->nextLine();
		}
		return $examples;
	}

	function shouldParseLine() {
		return substr(ltrim($this->getCurrentLine()), 0, 1) == '*';
	}

	function isSourceLine() {
		return preg_match('/^\s*\*\s*php>/', $this->getCurrentLine());
	}

	function hasNextLine() {
		return $this->lineno < count($this->lines);
	}

	function nextLine() {
		$this->lineno++;
		return $this->getCurrentLine();
	}

	function ungetLine() {
		$this->lineno--;
	}

	function getCurrentLine() {
		return @$this->lines[$this->lineno];
	}
}
